import overmind as overmind
import parser as parser
import utils as utils
import os
reload(overmind)

class Summoner():
	def __init__(self, id, data_cache = True, soup_cache = True):
		self.id = id
		self.get_data(data_cache, soup_cache)
	def get_data(self, data_cache, soup_cache):
		"""
		if data_cache is true it will attempt to get local pickle file, elif soup_cache==true
			it will attempt to get local html file, otherwise it will just download the html file
		get the data and re organize/add to it for this class
		"""
		self.data  = parser.get_summoner_data(self.id, data_cache, soup_cache)
		self.season_stats = self.data["stats"]
		for k in self.season_stats.keys():
			for champ_data in self.season_stats[k]:
				#rate the champ
				_c = champ_data
				gold_score = (_c["kills"] * 12) + _c["cs"] + ( _c["assists"] * 4 )
				_c["support_rating"] = _c["assists_ratio"]
				_c["rating"] = gold_score * _c["kill_ratio"]
				_c["rankings"] = self.get_champ_tag_rankings(_c)
				_c["tags"] = overmind.CHAMP_TAGS[_c["name"]]

	def get_champ_tag_rankings(self, champ_data):
		champ_ranking = {}
		for tag in overmind.ALL_TAGS:

			if tag == "support":
				_rating = champ_data["support_rating"]
			else:
				_rating = champ_data["rating"]

			h,a,l = overmind.TAG_HIGH[tag], overmind.TAG_AVE[tag],  overmind.TAG_LOW[tag]
			if _rating < a:
				per = -1+(_rating-l)/(a-l)
			if _rating > a:
				per = 0+(_rating-a)/(h-a)
			champ_ranking[tag] = per
		return champ_ranking

	def get_champs(self, champ_names = [], tags = [], played = 0, season = "most recent"):
		"""
		get champs based on filters from arguements
		"""
		season_3 = self.season_stats.get("season_3")
		season_2 = self.season_stats.get("season_2")
		season_2_filtered, season_3_filtered = [], []
		if season_3:
			for champ_data in season_3:
				if filter_champ(champ_data, champ_names, tags):
					season_3_filtered.append(champ_data)
		if season_2:
			for champ_data in season_2:
				if filter_champ(champ_data, champ_names, tags):
					season_2_filtered.append(champ_data)

		#this is the final champ list we are looking for, return this list
		champ_data_list = []
		added_champ_names = [] #list of champ names that need no futher searching
		if season == "most recent" or season == 0 or season == None:
			#If there is enough games played in season 3, ignore data from season 2. otherwise, combine the data
			for champ_data in season_3_filtered:
				if champ_data["played"] >= played:
					added_champ_names.append(champ_data["name"])
					champ_data_list.append(champ_data)

				elif season_2:
					#get supplimemental data from season 2
					_supp_champ_data = get_champ_data_by_name(champ_data["name"], season_2)

					if not _supp_champ_data:
						continue
					combined_champ_data = combine_champ_data_dicts(champ_data, _supp_champ_data)

					if combined_champ_data["played"] >= played:
						champ_data_list.append(combined_champ_data)
						added_champ_names.append(combined_champ_data["name"])

			for champ_data in season_2_filtered:
				if champ_data["name"] in added_champ_names: continue
				if champ_data["played"] >= played:
					champ_data_list.append(champ_data)

		if season == "season_3" or season == "season 3" or season == 3:
			champ_data_list = season_3_filtered
		if season == "season_2" or season == "season 2" or season == 2:
			champ_data_list = season_2_filtered
		return champ_data_list

	def get_overall_tag_rankings(self):

		def _add_up_champ_ranking(champs):
			_played, _total_ranking, _div = 0, 0, 0
			for c in champs:
				_played += c["played"]
				_total_ranking += c["rankings"][tag]
				_div += 1
			return _played, _total_ranking, _div

		overall_rankings = {}
		for tag in overmind.ALL_TAGS:
			played = 0
			total_ranking = 0
			div = 0
			#check season 3 for champs played that have this tag
			champs = self.get_champs(tags=[tag], season=3)
			played, total_ranking, div = _add_up_champ_ranking(champs)
			#if there aren't enough played games, add in season 2
			if not played > 10:
				champs = self.get_champs(tags=[tag], season=2)
				played, total_ranking, div = _add_up_champ_ranking(champs)
			if played > 10:
				overall_rankings[tag] = total_ranking/div
		return overall_rankings

	def get_best_champs(self, min_ranking = -.1):
		champ_data_list = self.get_champs(played = 5)
		champ_ranking_list = []
		for champ_data in champ_data_list:
			ranking = self.get_champ_ranking(champ_data["name"])[0]
			if ranking > min_ranking:
				champ_ranking_list.append([ranking, champ_data["name"], champ_data["played"]])
		champ_ranking_list.sort()
		champ_ranking_list.reverse()
		return champ_ranking_list

	def get_champ_ranking(self, champ_name, tag = None, played = 4):
		#champs have multiple rankings because they have multiple tags. A ranking for each tag
		#this goes down a hierachy of tags, getting the most important/significant one for the champion first
		#it returns carry_ranking and support_ranking, one will be a number, the other will be None
		champ_data = self.get_champs(played = played, champ_names = [champ_name])
		if champ_data:
			champ_data = champ_data[0]
			played = champ_data["played"]
			if tag:
				tags = [tag]
			else:
				tags = champ_data["tags"]
			if "carry" in tags:
				ranking_type, ranking = "carry", champ_data["rankings"]["carry"]
			elif "assassin" in tags:
				ranking_type, ranking = "carry", champ_data["rankings"]["assassin"]
			elif "tank" in tags:
				ranking_type, ranking = "support", champ_data["rankings"]["support"]
			elif "fighter" in tags:
				ranking_type, ranking = "carry", champ_data["rankings"]["fighter"]
			elif "jungler" in tags:
				ranking_type, ranking = "carry", champ_data["rankings"]["mage"]
			elif "support" in tags:
				ranking_type, ranking = "support", champ_data["rankings"]["support"]
			elif "mage" in tags:
				ranking_type, ranking = "carry", champ_data["rankings"]["mage"]
		else:
			tags = overmind.CHAMP_TAGS[champ_name]
			if "carry" in tags or "assassin" in tags or "fighter" in tags or "mage" in tags:
				ranking, ranking_type, played = -.5, "carry", 0
			elif "support" in tags or "tank" in tags:
				ranking, ranking_type, played  = -.5, "support", 0
		return ranking, ranking_type, played


class MatchList():
	def __init__(self, id):
		self.id = id
		self.data = None
		self.match_list_file = os.path.join(overmind.MATCH_LIST_DIR, self.id)
		if os.path.isfile(self.match_list_file):
			self.data = utils.unpickle_data(self.match_list_file)

	def update(self, cache = True, match_type = "Ranked Solo 5v5"):
		soup = parser.get_summoner_soup_page(self.id, cache = cache)
		if not soup:
			return
		matches = parser.get_match_history_dict(soup, self.id, match_type = match_type)
		if not self.data:
			self.data = {}
			self.data["matches"] = matches
			self.data["meta"] = parser.get_meta_from_summoner_page(soup)
			utils.pickle_data(self.data, self.match_list_file)
			return
		if not matches:
			return
		matches.reverse()
		for m in matches:
			if not self.get_entry_by_date(m["date"]):
				self.data["matches"].insert(0, m)
		utils.pickle_data(self.data, self.match_list_file)

	def get_entry_by_date(self, date, match_list = None):
		if match_list == None:
			match_list = self.data["matches"]
		for m in match_list:
			if m["date"] == date:
				return m
		return None


#########
#UTILITIES
#########
def get_counter_score(ally_champs, enemy_champs):
	ally_rating, enemy_rating = 0, 0
	def _do(champ_list, against_champ_list):
		rating = 0
		message = ""
		for c in champ_list:
			counters = get_counter(c)
			for c_champ in counters:
				if c_champ in against_champ_list:
					rating += 1
					message += "%s counters %s\n"%(c_champ, c)
		return rating, message
	ally_rating, ally_message = _do(ally_champs, enemy_champs)
	enemy_rating, enemy_message = _do(enemy_champs, ally_champs)
	return 10-ally_rating, 10-enemy_rating, ally_message, enemy_message
	
def get_counter(champ):
	counter_list = overmind.COUNTERS.get(champ)
	if champ == "aaa":
		return []
	if not counter_list:
		print "warning: could not find counter for ", champ
		return []
	return counter_list

def restructure_team_data(_team):
	#restruct the data from match list "matches"
	_new_team = []
	for _p in _team:
		_np = {}
		_np["id"] = _p[1]
		_np["summoner"] = Summoner(_p[1])
		_np["champ"] = _p[0]
		_np["tag"] = None
		_new_team.append(_np)
	return _new_team

def combine_champ_data_dicts(champ_data1, champ_data2):
	new_champ_data = {}
	new_champ_data["rankings"] = {}
	p1, p2 = champ_data1["played"], champ_data2["played"]
	for k1, v1 in champ_data1.items():
		v2 = champ_data2.get(k1)
		if k1 == "rankings":
			for _k, _v in v1.items():
				new_champ_data["rankings"][_k] = ( (_v*p1) + (v2[_k]*p2))  / (p1 + p2)
		elif type(v2).__name__ == "float" and type(v1).__name__ == "float":
			new_champ_data[k1] = ( (v1 * p1) + (v2 * p2) ) / (p1 + p2)
		else:
			new_champ_data[k1] = v1
	return new_champ_data

def get_champ_data_by_name(name, champ_data_list):
	for champ_data in champ_data_list:
		if champ_data["name"] == name:
			return champ_data
	return None

def filter_champ(champ_data, champ_names, tags):
	if champ_names:
		if not champ_data["name"] in champ_names:
			return False
	if tags:
		_c_tags = overmind.CHAMP_TAGS.get(champ_data["name"])
		if not _c_tags:
			print "WARNING: could not find champ %s"%champ_data["name"]
		for t in tags:
			if not t in _c_tags:
				return False
	return True


def analyze_team(team):
	carry_total = 0
	support_total = 0
	break_down = {}
	for player in team:
		selected_champ = player.get("champ")
		if not selected_champ:
			continue
		s = player.get("summoner", Summoner(player["id"]))
		ranking, ranking_type, played = s.get_champ_ranking(selected_champ, player.get("tag"), played = 1)
		if ranking_type == "carry": carry_total += ranking
		if ranking_type == "support": support_total += ranking
		break_down[player["id"]] = (ranking, ranking_type, selected_champ, played)
	return carry_total, support_total, break_down

def tests2():
	s = Summoner(overmind.MY_ID)
	print s.get_overall_tag_rankings()
	print s.get_best_champs()

def tests():
	ids = ["32763225", "24682068", "20615541", "29830524", "34683760", "20976333", "28790666"]
	matches = []
	for i in ids:
		ml = MatchList(i)
		#ml.update(False)
		matches += ml.data["matches"]

	prediction_count = 0
	success = 0

	total_predictions = 0
	correct_predictions = 0
	total_ranking = 0
	total_sup_ranking = 0

	total_played = 0
	total_won = 0
	total_games = 0
	for m in matches:
		allies = restructure_team_data(m["team"]["allies"])
		enemies = restructure_team_data(m["team"]["enemies"])

		print "\n"
		print m["outcome"]
		a_res = analyze_team(allies)
		e_res = analyze_team(enemies)
		print a_res[:2]
		print e_res[:2]
		total_games+= 1
		min_sup = -.4

		if a_res[0]> 4.0:
			min_sup = -(round(a_res[0])/10)

		dif = a_res[0] - e_res[0]
		dif2 = ( a_res[1] + a_res[0] ) - ( e_res[1] + e_res[0] )
		if dif > 2.0 and a_res[1]>0.0 or dif2 > 3.0:
			print "guess!"
			total_predictions += 1
			total_ranking += a_res[0]
			total_sup_ranking += a_res[1]
			if m["outcome"] == "win":
				correct_predictions += 1

		if a_res[0] > -.1 and a_res[0] > -0.5:
			tog = True
			for p, score in a_res[2].items():
				if score[0] < -.7:
					tog = False
			if tog:
				total_played += 1
				if m["outcome"] == "win":
					total_won += 1
		

	print correct_predictions/float(total_predictions)
	print correct_predictions, total_predictions
	#print total_ranking/total_predictions
	#print total_sup_ranking/total_predictions
	print total_won/float(total_played)
	print total_won, total_played, total_games

			
def test3():
	selected_champ = "ezreal"
	s = Summoner("28790666")
	print s.get_champ_ranking(selected_champ, played=4)